package com.dempsey.gateway.config;

import com.dempsey.gateway.handler.ScAuthenticationEntryPointHandler;
import com.dempsey.gateway.filter.ScFilter;
import com.dempsey.gateway.handler.ScAccessDeniedHandler;
import com.dempsey.gateway.service.ScAuthenticationManager;
import com.dempsey.gateway.service.ScAuthorizationManager;
import com.dempsey.gateway.service.ScSecurityContextRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;

/**
 * @author zhe.xiao
 * @date 2021-04-12 17:02
 * @description
 */
@Configuration
@EnableWebFluxSecurity
public class WebSecurityConfig {

    private final String[] permitUrls = {"/auth/captcha","/auth/login","/auth/register",
            "/good/getHome",
            "/file/**"};

    // 把header拿到的token放入AuthenticationToken
    @Autowired
    ScSecurityContextRepository scSecurityContextRepository;

    // 从AuthenticationToken读取Token并做用户数据解析
    @Autowired
    ScAuthenticationManager scAuthenticationManager;

    // 权限验证，是否放行
    @Autowired
    ScAuthorizationManager scAuthorizationManager;

    // 认证失败处理类
    @Autowired
    ScAccessDeniedHandler scAccessDeniedHandler;

    // 认证失败执行
    @Autowired
    ScAuthenticationEntryPointHandler scAuthenticationEntryPoint;

    // 密码加密方式
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 访问权限授权
     *
     * @param http
     * @return
     */
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.csrf().disable()
                .securityContextRepository(scSecurityContextRepository) //存储认证信息
                .authenticationManager(scAuthenticationManager) //认证管理
                .authorizeExchange(exchange -> exchange // 请求拦截处理
                        .pathMatchers(this.permitUrls).permitAll()
                        .pathMatchers(HttpMethod.OPTIONS).permitAll()
                        .anyExchange().access(scAuthorizationManager) //权限
                )
                .addFilterAfter(new ScFilter(), SecurityWebFiltersOrder.AUTHORIZATION) //拦截处理
                .exceptionHandling().accessDeniedHandler(scAccessDeniedHandler) //权限认证失败
                .and()
                .exceptionHandling().authenticationEntryPoint(scAuthenticationEntryPoint); //认证失败

        return http.build();
    }
}